using Lazy.Captcha.Core.Generator;
using Lazy.Captcha.Core;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Cors;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using SMARTHOTEL.EntityFrameworkCore;
using SMARTHOTEL.MultiTenancy;
using Swashbuckle.AspNetCore.Filters;
using Swashbuckle.AspNetCore.SwaggerUI;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Volo.Abp;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.AntiForgery;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared;
using Volo.Abp.AspNetCore.Serilog;
using Volo.Abp.Autofac;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.Swashbuckle;
using Volo.Abp.UI.Navigation.Urls;
using Volo.Abp.VirtualFileSystem;
using StackExchange.Redis;
using Yitter.IdGenerator;

using System.Net.Http;
using Essensoft.Paylink.Alipay;
using SMARTHOTEL.Alipay;

namespace SMARTHOTEL;

[DependsOn(
 
    typeof(AbpAutofacModule),
    typeof(SMARTHOTELApplicationModule),
    typeof(SMARTHOTELEntityFrameworkCoreModule),
    typeof(AbpAspNetCoreMvcUiLeptonXLiteThemeModule),
    typeof(AbpAspNetCoreSerilogModule),
    typeof(AbpSwashbuckleModule),
    typeof(AbpAutofacModule) 
    
)]
public class SMARTHOTELHttpApiHostModule : AbpModule
{


    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        Configure<AbpAntiForgeryOptions>(a =>
        {
            a.TokenCookie.Expiration = TimeSpan.FromDays(1);
            a.AutoValidate = false;
        });



        var configuration = context.Services.GetConfiguration();
        foreach (var config in configuration.GetChildren())
        {
            Console.WriteLine($"{config.Key}: {config.Value}");
        }
        var hostingEnvironment = context.Services.GetHostingEnvironment();
        // 配置上下文
        context.Services.AddHttpContextAccessor();
        Yitter.IdGenerator.YitIdHelper.SetIdGenerator(new Yitter.IdGenerator.IdGeneratorOptions());
        
        context.Services.AddCaptcha(context.Services.GetConfiguration());
        // 注册 Redis 分布式缓存服务 (IDistributedCache)
        // 注册 Redis 服务
        //context.Services.AddStackExchangeRedisCache(options =>
        //{
        //    // 正确读取 Redis 连接字符串
        //    options.Configuration = context.Services.GetConfiguration().GetConnectionString("Redis");
        //    //options.InstanceName = "captcha:";
        //});

        // 添加Paylink依赖注入
        context.Services.AddAlipay();

        // 在 appsettings.json(开发环境：appsettings.Development.json) 中 配置选项
        context.Services.Configure<AlipayOptions>(configuration.GetSection("Alipay"));




        ////// 从配置中读取 AlipayOptions 并注册
        //var alipaySection = context.Services.GetConfiguration().GetSection("Alipay");
        //if (!alipaySection.Exists())
        //{
        //    throw new Exception("Alipay section is missing in configuration!");
        //}

        //var alipayOptions = alipaySection.Get<AlipayOptions>();
        //if (alipayOptions == null)
        //{
        //    throw new Exception("Failed to bind AlipayOptions from configuration!");
        //}
        //context.Services.Configure<AlipayOptions>(context.Services.GetConfiguration().GetSection("Alipay"));

        //// 注册 AlipayOptions 的直接实例（如果需要）
        //context.Services.AddSingleton(resolver =>
        //    resolver.GetRequiredService<IOptions<AlipayOptions>>().Value);

        //// 注册 IHttpClientFactory
        //context.Services.AddHttpClient();

        //// 注册 AlipayPublicKeyManager
        //context.Services.AddSingleton<AlipayPublicKeyManager>();

        //// 注册 IAlipayClient 和 IAlipayNotifyClient
        //context.Services.AddSingleton<IAlipayClient, AlipayClient>();


        //// 注册 IAlipayClient 和 IAlipayNotifyClient
        //context.Services.AddSingleton<IAlipayClient, AlipayClient>();
        //context.Services.AddSingleton<IAlipayNotifyClient, AlipayNotifyClient>();

        //// 注册 AlipayMethod
        //context.Services.AddTransient<AlipayMethod>();

        ConfigureCaptcah(context);
        ConfigureAuthentication(context);
        ConfigureBundles();
        ConfigureUrls(configuration);
        ConfigureConventionalControllers();
        ConfigureLocalization();
        ConfigureVirtualFileSystem(context);
        ConfigureCors(context, configuration);
        ConfigureSwaggerServices(context, configuration);
    }

    private void ConfigureCaptcah(ServiceConfigurationContext context)
    {
        // 全部配置
        context.Services.AddCaptcha(context.Services.GetConfiguration(), option =>
        {
            option.CaptchaType = CaptchaType.WORD; // 验证码类型
            option.CodeLength = 6; // 验证码长度, 要放在CaptchaType设置后.  当类型为算术表达式时，长度代表操作的个数
            option.ExpirySeconds = 30; // 验证码过期时间
            option.IgnoreCase = true; // 比较时是否忽略大小写
            option.StoreageKeyPrefix = ""; // 存储键前缀

            option.ImageOption.Animation = true; // 是否启用动画
            option.ImageOption.FrameDelay = 30; // 每帧延迟,Animation=true时有效, 默认30

            option.ImageOption.Width = 150; // 验证码宽度
            option.ImageOption.Height = 50; // 验证码高度
            option.ImageOption.BackgroundColor = SkiaSharp.SKColors.White; // 验证码背景色

            option.ImageOption.BubbleCount = 2; // 气泡数量
            option.ImageOption.BubbleMinRadius = 5; // 气泡最小半径
            option.ImageOption.BubbleMaxRadius = 15; // 气泡最大半径
            option.ImageOption.BubbleThickness = 1; // 气泡边沿厚度

            option.ImageOption.InterferenceLineCount = 2; // 干扰线数量

            option.ImageOption.FontSize = 36; // 字体大小
            option.ImageOption.FontFamily = DefaultFontFamilys.Instance.Actionj; // 字体

            /* 
             * 中文使用kaiti，其他字符可根据喜好设置（可能部分转字符会出现绘制不出的情况）。
             * 当验证码类型为“ARITHMETIC”时，不要使用“Ransom”字体。（运算符和等号绘制不出来）
             */

            option.ImageOption.TextBold = true;// 粗体，该配置2.0.3新增
        });
    }

    private void ConfigureAuthentication(ServiceConfigurationContext context)
    {
        var configuration = context.Services.GetConfiguration();
        //Jwt
        context.Services.AddAuthentication(option =>
        {
            option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        }).AddJwtBearer(
                        option =>
                        {
                            option.TokenValidationParameters = new TokenValidationParameters
                            {
                                //是否验证发行人
                                ValidateIssuer = true,
                                ValidIssuer = configuration["JwtConfig:Bearer:Issuer"],//发行人

                                //是否验证受众人
                                ValidateAudience = true,
                                ValidAudience = configuration["JwtConfig:Bearer:Audience"],//受众人

                                //是否验证密钥
                                ValidateIssuerSigningKey = true,
                                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["JwtConfig:Bearer:SecurityKey"])),

                                ValidateLifetime = true, //验证生命周期

                                RequireExpirationTime = true, //过期时间

                                ClockSkew = TimeSpan.FromSeconds(30)   //平滑过期偏移时间
                            };
                        }
                    );
    }

    private void ConfigureBundles()
    {
        Configure<AbpBundlingOptions>(options =>
        {
            options.StyleBundles.Configure(
                LeptonXLiteThemeBundles.Styles.Global,
                bundle =>
                {
                    bundle.AddFiles("/global-styles.css");
                }
            );
        });
    }

    private void ConfigureUrls(IConfiguration configuration)
    {
        Configure<AppUrlOptions>(options =>
        {
            options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"];
            options.RedirectAllowedUrls.AddRange(configuration["App:RedirectAllowedUrls"].Split(','));

            //options.Applications["Angular"].RootUrl = configuration["App:ClientUrl"];
            //options.Applications["Angular"].Urls[AccountUrlNames.PasswordReset] = "account/reset-password";
        });
    }

    private void ConfigureVirtualFileSystem(ServiceConfigurationContext context)
    {
        var hostingEnvironment = context.Services.GetHostingEnvironment();

        if (hostingEnvironment.IsDevelopment())
        {
            Configure<AbpVirtualFileSystemOptions>(options =>
            {
                options.FileSets.ReplaceEmbeddedByPhysical<SMARTHOTELDomainSharedModule>(
                    Path.Combine(hostingEnvironment.ContentRootPath,
                        $"..{Path.DirectorySeparatorChar}SMARTHOTEL.Domain.Shared"));
                options.FileSets.ReplaceEmbeddedByPhysical<SMARTHOTELDomainModule>(
                    Path.Combine(hostingEnvironment.ContentRootPath,
                        $"..{Path.DirectorySeparatorChar}SMARTHOTEL.Domain"));
                options.FileSets.ReplaceEmbeddedByPhysical<SMARTHOTELApplicationContractsModule>(
                    Path.Combine(hostingEnvironment.ContentRootPath,
                        $"..{Path.DirectorySeparatorChar}SMARTHOTEL.Application.Contracts"));
                options.FileSets.ReplaceEmbeddedByPhysical<SMARTHOTELApplicationModule>(
                    Path.Combine(hostingEnvironment.ContentRootPath,
                        $"..{Path.DirectorySeparatorChar}SMARTHOTEL.Application"));
            });
        }
    }

    private void ConfigureConventionalControllers()
    {
        Configure<AbpAspNetCoreMvcOptions>(options =>
        {
            options.ConventionalControllers.Create(typeof(SMARTHOTELApplicationModule).Assembly);
        });
    }

    private static void ConfigureSwaggerServices(ServiceConfigurationContext context, IConfiguration configuration)
    {
        context.Services.AddSwaggerGen(
     options =>
     {
      

         options.SwaggerDoc("v2", new OpenApiInfo { Title = "业务接口", Version = "v2" });
         options.SwaggerDoc("v3", new OpenApiInfo { Title = "支付接口", Version = "v3" });
         options.DocInclusionPredicate((doc, desc) =>
         {
             return desc.GroupName == doc;
         });


         //开启权限小锁
         options.OperationFilter<AddResponseHeadersFilter>();
         options.OperationFilter<AppendAuthorizeToSummaryOperationFilter>();
         options.OperationFilter<SecurityRequirementsOperationFilter>();
         options.CustomSchemaIds(type => type.FullName);

         //给参数设置默认值
         //options.SchemaFilter<SchemaFilter>();

         //在header中添加token，传递到后台
         options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
         {
             Description = "JWT授权(数据将在请求头中进行传递)直接在下面框中输入Bearer {token}(注意两者之间是一个空格) \"",
             Name = "Authorization",//jwt默认的参数名称
             In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
             Type = SecuritySchemeType.ApiKey
         });

         //就是这里！！！！！！！！！
         var basePath = AppDomain.CurrentDomain.BaseDirectory;
         var xmlPath = Path.Combine(basePath, "SMARTHOTEL.Application.xml");//这个就是刚刚配置的xml文件名
         options.IncludeXmlComments(xmlPath, true);//默认的第二个参数是false，这个是controller的注释，记得修改
     }
 );

    }
    

    private void ConfigureLocalization()
    {
        Configure<AbpLocalizationOptions>(options =>
        {
            options.Languages.Add(new LanguageInfo("ar", "ar", "العربية"));
            options.Languages.Add(new LanguageInfo("cs", "cs", "Čeština"));
            options.Languages.Add(new LanguageInfo("en", "en", "English"));
            options.Languages.Add(new LanguageInfo("en-GB", "en-GB", "English (UK)"));
            options.Languages.Add(new LanguageInfo("fi", "fi", "Finnish"));
            options.Languages.Add(new LanguageInfo("fr", "fr", "Français"));
            options.Languages.Add(new LanguageInfo("hi", "hi", "Hindi", "in"));
            options.Languages.Add(new LanguageInfo("is", "is", "Icelandic", "is"));
            options.Languages.Add(new LanguageInfo("it", "it", "Italiano", "it"));
            options.Languages.Add(new LanguageInfo("hu", "hu", "Magyar"));
            options.Languages.Add(new LanguageInfo("pt-BR", "pt-BR", "Português"));
            options.Languages.Add(new LanguageInfo("ro-RO", "ro-RO", "Română"));
            options.Languages.Add(new LanguageInfo("ru", "ru", "Русский"));
            options.Languages.Add(new LanguageInfo("sk", "sk", "Slovak"));
            options.Languages.Add(new LanguageInfo("tr", "tr", "Türkçe"));
            options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文"));
            options.Languages.Add(new LanguageInfo("zh-Hant", "zh-Hant", "繁體中文"));
            options.Languages.Add(new LanguageInfo("de-DE", "de-DE", "Deutsch", "de"));
            options.Languages.Add(new LanguageInfo("es", "es", "Español", "es"));
            options.Languages.Add(new LanguageInfo("el", "el", "Ελληνικά"));
        });
    }

    private void ConfigureCors(ServiceConfigurationContext context, IConfiguration configuration)
    {
        context.Services.AddCors(options =>
        {
            options.AddDefaultPolicy(builder =>
               {
                builder
                    .WithOrigins(
                        configuration["App:CorsOrigins"]
                            .Split(",", StringSplitOptions.RemoveEmptyEntries)
                            .Select(o => o.RemovePostFix("/"))
                            .ToArray()
                    )
                    .WithAbpExposedHeaders()
                    .SetIsOriginAllowedToAllowWildcardSubdomains()
                    .AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowCredentials();
            });
        });
    }

    public override void OnApplicationInitialization(ApplicationInitializationContext context)
    {
        var app = context.GetApplicationBuilder();
        var env = context.GetEnvironment();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseAbpRequestLocalization();

        if (!env.IsDevelopment())
        {
            app.UseErrorPage();
        }

  


        //读取静态文件
        app.UseStaticFiles();
        app.UseCorrelationId();
        app.UseRouting();
        app.UseCors(x=>x.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
        app.UseAuthentication();
        //app.UseAbpOpenIddictValidation();

        //if (MultiTenancyConsts.IsEnabled)
        //{
        //    app.UseMultiTenancy();
        //}

        app.UseUnitOfWork();
        app.UseAuthorization();

        app.UseSwagger();


        app.UseSwaggerUI(c =>
        {
            c.SwaggerEndpoint("/swagger/v2/swagger.json", "业务接口");
            c.SwaggerEndpoint("/swagger/v3/swagger.json", "支付接口");
            // 模型的默认扩展深度，设置为 -1 完全隐藏模型
            c.DefaultModelsExpandDepth(1);
            // API文档仅展开标记
            c.DocExpansion(DocExpansion.List);
            c.DefaultModelRendering(ModelRendering.Example);
            c.DefaultModelExpandDepth(-1);
            // API前缀设置为空
            c.RoutePrefix = string.Empty;
            // API页面Title
            c.DocumentTitle = "😍接口文档 - 阿星Plus⭐⭐⭐";
        });


        app.UseAuditing();
        app.UseAbpSerilogEnrichers();
        app.UseConfiguredEndpoints();
    }
}
